package cn.itsource.user.service.impl;

import cn.itsource.basic.dot.BinderDto;
import cn.itsource.basic.dot.LoginDto;
import cn.itsource.basic.exception.BusinessException;
import cn.itsource.basic.jwt.JwtUtils;
import cn.itsource.basic.jwt.LoginData;
import cn.itsource.basic.jwt.RsaUtils;
import cn.itsource.basic.service.impl.BaseServiceImpl;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.HttpUtil;
import cn.itsource.basic.util.Md5Utils;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.menu.domain.Menu;
import cn.itsource.org.mapper.EmployeeMapper;
import cn.itsource.user.constants.WxConstant;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.domain.Wxuser;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.mapper.WxuserMapper;
import cn.itsource.user.service.ILogininfoService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务实现类：
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Override
    public AjaxResult accountLogin(LoginDto loginDto) {
        String username = loginDto.getAccount();
        String password = loginDto.getCheckPass();
        //1.校验
        //1.1.空值校验
        if (StringUtils.isEmpty(username)
                || StringUtils.isEmpty(password)) {
            throw new BusinessException("请输入合法信息!!!");
        }

        Logininfo logininfo = logininfoMapper.loadByAccount(loginDto);
        if (logininfo == null) {
            throw new BusinessException("用户名或密码错误!!!");
        }
        //1.2.用户名或密码【加密加盐】校验
        String dbMd5Pwd = logininfo.getPassword();
        String md5Pwd = Md5Utils.encrypByMd5(password + logininfo.getSalt());
        if (!dbMd5Pwd.equals(md5Pwd)) {
            throw new BusinessException("用户名或密码错误!!!");
        }

        //1.3.状态校验 - 启用，禁用
        if (!logininfo.getDisable()) {
            throw new BusinessException("你的账号被封禁，请联系管理员!!!");
        }

        Map<String, Object> map = loginSuccessJwtHandler(logininfo);

        return AjaxResult.me().setResultObj(map);
    }

    @Override
    public AjaxResult wechatLogin(String code) {
        //1.根据code发送请求获取token和openid
        String url = WxConstant.GET_ACK_URL
                .replace("APPID", WxConstant.APPID)
                .replace("SECRET", WxConstant.SECRET)
                .replace("CODE", code);
        String jsonStr = HttpUtil.httpGet(url);
        //        System.out.println(jsonStr);

        //{"access_token":"57_3R0PHzOIKX6brh1TbBZKqwsOCHugjzrJeDZgssoAmsF_UFOq-TSTXE3tmZBUr7VIZ_eP71LhIzOeLeh4gua3vVligjDuBCjRiImEAPSAwqc","openid":"oa9wA01X4TNik8bbXWklIyArUZ5c",}
        //2.将响应的json字符串 转成 json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");

        //3.通过openid去t_wxuser中查询
        Wxuser wxuser = wxuserMapper.findByOpenid(openid);

        //3.1.查到了=以前扫过码 = 直接免密登陆【不需要在页面中输入用户名和密码就可以登陆】
        //如果通过openid查询到了微信用户对象
        if (wxuser != null) {
            //疑问：user_id可能为null吗？只要有wxuser，就一定会绑定user_id
            User user = userMapper.findById(wxuser.getUserId());
            if (user != null) { //并且关联的User对象也有值 - 绑定了 - 后续扫码 - 免密登陆
                Logininfo logininfo = logininfoMapper.findById(user.getLogininfoId());

//                String token = UUID.randomUUID().toString();//36位随机字符串
//
//                //封住返回值：Map【token，logininfo】
//                Map<String, Object> map = new HashMap<>();
//                map.put("token",token);
//                logininfo.setSalt(null);
//                logininfo.setPassword(null);
//                map.put("logininfo",logininfo);
                Map<String, Object> map = loginSuccessJwtHandler(logininfo);

                return AjaxResult.me().setResultObj(map);
            }
        }

        //3.2.如果没有查到 = 响应给前端token，openid，前端跳转到绑定页面
        return AjaxResult.me().setSuccess(false).setResultObj("?access_token=" + access_token + "&openid=" + openid);
    }

    @Override
    public AjaxResult wechatBinder(BinderDto binderDto) {
        //获取数据
        String phone = binderDto.getPhone();
        String verifyCode = binderDto.getVerifyCode();
        String accessToken = binderDto.getAccessToken();
        String openId = binderDto.getOpenId();
        //校验
        //判断空值
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode) || StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)) {
            throw new BusinessException("请正确输入信息");
        }
        //验证码
        Object codestr = redisTemplate.opsForValue().get("binder" + phone);
        if (codestr == null) {
            throw new BusinessException("验证码已过期");
        }
        if (!codestr.toString().split(":")[0].equals(verifyCode)) {
            throw new BusinessException("请输入正确的验证码");
        }
        //绑定用户：t_wxUser【user_id】 绑定 t_user
        //4.获取WxUser - 发送第三个请求 - json字符串
        String url = WxConstant.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String jsonStr = HttpUtil.httpGet(url);
        //响应的是json字符串，需转换为json对象
        Wxuser wxuser = jsonStr2Wxuser(jsonStr);
        /*
        *{
        "openid":"OPENID",
        "nickname":"NICKNAME",
        "sex":1,
        "province":"PROVINCE",
        "city":"CITY",
        "country":"COUNTRY",
        "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
        "privilege":[
        "PRIVILEGE1",
        "PRIVILEGE2"
        ],
        "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"`
        }
        * */
        //根据openid查询数据库中是否存在user
        User user1 = userMapper.findByPhone(phone);
        if (user1 == null) {
            //获取user1数据
            user1 = binderDto2user(binderDto);
            //获取logininfo数据
            Logininfo logininfo = user2logininfo(user1);
            //先将logininfo添加到数据库
            logininfoMapper.add(logininfo);
            //logininfo生成自增长id赋值给user
            user1.setLogininfoId(logininfo.getId());
            //后将user添加到数据库
            userMapper.add(user1);
        }
        //将userid数据保存到wxuser中的userid中
        wxuser.setUserId(user1.getId());
        //保存weuser数据
        wxuserMapper.add(wxuser);

        //进行免密登录  返回给前端用户登录信息(logininfo)和一个随机的token值
        //用户信息
        Logininfo logininfo = logininfoMapper.findById(user1.getLogininfoId());
//        //uuid生成随机数
//        String token = UUID.randomUUID().toString();
//
//        //将数据保存到map中返回给前端
//        Map<Object, Object> map = new HashMap<>();
//        map.put("token",token);
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("logininfo",logininfo);
        Map<String, Object> map = loginSuccessJwtHandler(logininfo);
        return AjaxResult.me().setResultObj(map);
    }

    private Map<String, Object> loginSuccessJwtHandler(Logininfo logininfo) {
        //数据存储在map中方便和前台获取用户名
        HashMap<String, Object> map = new HashMap<>();
        map.put("logininfo", logininfo);
        //得到四个参数
        LoginData loginData = new LoginData();
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        loginData.setLogininfo(logininfo);
        //判断用户是否是管理员，用户直接放行不需要权限
        if (logininfo.getType() == 0) {
            //查询管理员权限
            List<String> permissions = employeeMapper.findSns(logininfo.getId());
            //权限放入到map
            map.put("permissions", permissions);
            //权限设置到logiddata中
            loginData.setPermissions(permissions);
            //获取菜单权限
            List<Menu> menus = employeeMapper.findMenus(logininfo.getId());
            map.put("menus", menus);
            loginData.setMenus(menus);
        }
        try {
            //获取私钥
            PrivateKey privateKey = RsaUtils.getPrivateKey(LogininfoServiceImpl.class.getClassLoader().getResource("auth_rsa.pri").getFile());
            //数据加密
            String token = JwtUtils.generateTokenExpireInMinutes(loginData, privateKey, 30);
            //将token装入到map中
            map.put("token", token);
            //return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;

    }

    private Wxuser jsonStr2Wxuser(String jsonStr) {
        //json格式字符串转换为json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        //创建一个微信用户获取对象数据
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(jsonObject.getString("openid"));
        wxuser.setNickname(jsonObject.getString("nickname"));
        //现在微信已经将性别
        wxuser.setSex(Integer.parseInt(jsonObject.getString("sex")));
        //地址：country + province + city
        wxuser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxuser.setUnionid(jsonObject.getString("unionid"));
        return wxuser;
    }

    private Logininfo user2logininfo(User user) {
        //获取logininfo对象
        Logininfo logininfo = new Logininfo();
        //将usrr数据复制给logininfo对象
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        logininfo.setDisable(true);
        return logininfo;
    }

    private User binderDto2user(BinderDto binderDto) {
        //加密加盐
        String salt = StrUtils.getComplexRandomString(64);
        String pwd = StrUtils.getComplexRandomString(6);
        String md5pwd = Md5Utils.encrypByMd5(pwd + salt);
        //获取user对象
        User user = new User();
        user.setPhone(binderDto.getPhone());
        user.setUsername(binderDto.getPhone());
        user.setPassword(md5pwd);
        return user;
    }

}
